#include "./WizInnerThread.hpp"
#include "../../Include/DataType/SmartPtr/SharedPtr/WizDataTypeSharedPtr.hpp"

namespace Wiz
{
    namespace Thread
    {
        ////////////////////////////////////////////////////////////////////////
        namespace TLS
        {
            namespace DataNode
            {
                struct Type
                {
                    ::Wiz::Void::ConstPtr                               m_Key;
                    ::Wiz::Thread::TLS::CleanUpFunction::SharedPtr      m_FuncPtr;
                    ::Wiz::Void::Ptr                                    m_Value;
                    Type*                                               m_Next;

                    Type(::Wiz::Void::ConstPtr Key, ::Wiz::Thread::TLS::CleanUpFunction::SharedPtr FuncPtr, ::Wiz::Void::Ptr Val, Type* Nxt)
                        : m_Key(Key), m_FuncPtr(FuncPtr), m_Value(Val), m_Next(Nxt)
                    {}
                };
            } /// end of namespace DataNode

            struct MainThread_t : public ::Wiz::Thread::Runnable::Type
            {
                MainThread_t()
                {
                    m_AutoRM = ::Wiz::Bool::False;
                    m_TLSDataNodePtr = WIZ_NULLPTR;
                }
                ::Wiz::Void::Type Run()
                {
                }
            };
            static MainThread_t MainThreadRunnable;

            ::Wiz::Thread::TLS::DataNode::Type* FindData(::Wiz::Void::ConstPtr Key)
            {
                ::Wiz::Thread::Runnable::Ptr const CurrRunnablePtr(::Wiz::Inner::Thread::TLS::GetCurrentRunnablePtr());
                if (::Wiz::IsValidPtr(CurrRunnablePtr))
                {
                    ::Wiz::Thread::TLS::DataNode::Type* CurrNodePtr = CurrRunnablePtr->m_TLSDataNodePtr;
                    while (::Wiz::IsValidPtr(CurrNodePtr))
                    {
                        if (CurrNodePtr->m_Key == Key)
                        {
                            return CurrNodePtr;
                        }
                        CurrNodePtr = CurrNodePtr->m_Next;
                    }

                    return WIZ_NULLPTR;
                }
                ::Wiz::Inner::Thread::TLS::SetCurrentRunnablePtr(::Wiz::Cast::Static<::Wiz::Void::Ptr>(&MainThreadRunnable));
                return FindData(Key);
            }

            ::Wiz::Void::Type SetData
                (
                ::Wiz::Void::ConstPtr                           Key,
                ::Wiz::Thread::TLS::CleanUpFunction::SharedPtr  FuncPtr,
                ::Wiz::Void::Ptr                                TLSDataPtr,
                ::Wiz::Bool::Type                               CleanUpExisting
                )
            {
                ::Wiz::Thread::TLS::DataNode::Type* const CurrNodePtr = FindData(Key);
                if (::Wiz::IsValidPtr(CurrNodePtr))
                {
                    if(CleanUpExisting && ::Wiz::IsValidPtr(CurrNodePtr->m_FuncPtr.Get()))
                    {
                        (*CurrNodePtr->m_FuncPtr)(CurrNodePtr->m_Value);
                    }
                    CurrNodePtr->m_FuncPtr=FuncPtr;
                    CurrNodePtr->m_Value=TLSDataPtr;
                }
                else
                {
                    ::Wiz::Thread::Runnable::Ptr CurrRunnablePtr(::Wiz::Inner::Thread::TLS::GetCurrentRunnablePtr());
                    if (::Wiz::IsValidPtr(CurrRunnablePtr))
                    {
                        ::Wiz::Thread::TLS::DataNode::Type* const NewNode = 
                            ::Wiz::Memory::Placement::New<::Wiz::Memory::Allocator::Heap::Type, ::Wiz::Thread::TLS::DataNode::Type>(Key, FuncPtr, TLSDataPtr, CurrRunnablePtr->m_TLSDataNodePtr);
                        CurrRunnablePtr->m_TLSDataNodePtr = NewNode;
                        return;
                    }
                    WIZ_ASSERT(::Wiz::Bool::False);
                }
            }

            ::Wiz::Void::Ptr GetData(::Wiz::Void::ConstPtr Key)
            {
                ::Wiz::Thread::TLS::DataNode::Type* const CurrNodePtr = FindData(Key);
                if (::Wiz::IsValidPtr(CurrNodePtr))
                {
                    return CurrNodePtr->m_Value;
                }
                return NULL;
            }
        } /// end of namespace TLS
        ////////////////////////////////////////////////////////////////////////
    } /// end of namespace Thread
} /// end of namespace Wiz

